#include <QMenuBar>
#include <QTabWidget>
#include <QSplitter>
#include <QListWidget>
#include <QLabel>
#include <QPushButton>
#include <QVBoxLayout>
#include <QHBoxLayout>
#include <QDebug>
#include <QKeyEvent>
#include <QStatusBar>
#include <QMessageBox>
#include <QDir>
#include <QFileInfo>
#include <QProcess>

#include <windows.h>

#include "../database/databasemanager.h"
#include "../brandpageparser.h"
#include "../modelpageparser.h"
#include "../parameterspageparser.h"
#include "../utils.h"
#include "../constants.h"
#include "imageswindow.h"
#include "videolinkwindow.h"
#include "paramswindow.h"
#include "pagedler.h"

namespace Jcr
{

static const int LinkRole = Qt::UserRole + 199;
PageDler::PageDler(QWidget* parent) : QMainWindow(parent)
{
    setWindowTitle(tr("Page Downloader"));
    statusBar()->show();

    QMenu* fileMenu = menuBar()->addMenu(tr("File"));

    m_startAct = new QAction(tr("Start"), this);
    connect(m_startAct, SIGNAL(triggered()), this, SLOT(getModels()));
    fileMenu->addAction(m_startAct);

    QSplitter* mainWidget = new QSplitter(Qt::Horizontal, this);
    m_modelList = new QListWidget(this);
    m_modelList->setAlternatingRowColors(true);
    m_modelList->setMaximumWidth(200);

    QHBoxLayout* topRightLayout = new QHBoxLayout;
    m_brandLabel = new QLabel(this);
    m_gotImageLabel = new QLabel(this);

    m_execLabel = new QLabel(this);
    m_execLabel->setText(tr("Hold on ..."));
    topRightLayout->addWidget(m_execLabel);

    QFont f;
    f.setBold(true);
    m_statusLabel = new QLabel(this);
    statusBar()->insertPermanentWidget(0, m_statusLabel, 100);

    m_gotImageLabel->setFont(f);
    statusBar()->insertPermanentWidget(1, m_gotImageLabel, 100);

    m_leftCountLabel = new QLabel(this);
    statusBar()->insertPermanentWidget(2, m_leftCountLabel, 100);

    m_execButton = new QPushButton(tr("Exec"), this);
    topRightLayout->addWidget(m_brandLabel);
    topRightLayout->addStretch();
    topRightLayout->addWidget(m_execButton);
    m_execButton->setShortcut(QKeySequence("Ctrl + R"));

    m_autoPilotButton = new QPushButton(tr("Auto Pilot"), this);
    m_autoPilotButton->setCheckable(true);
    topRightLayout->addWidget(m_autoPilotButton);

    m_locateButton = new QPushButton(tr("Locate"), this);
    topRightLayout->addWidget(m_locateButton);

    QWidget* rightWidget = new QWidget(this);
    QVBoxLayout* rightWidgetLayout = new QVBoxLayout;
    rightWidgetLayout->addLayout(topRightLayout);

    QSplitter* windowTabs = new QSplitter(this);
    rightWidgetLayout->addWidget(windowTabs);
    rightWidget->setLayout(rightWidgetLayout);

    m_imagesWindow = new ImagesWindow(this);
    m_paramsWindow = new ParamsWindow(this);
    m_videoLinkWindow = new VideoLinkWindow(this);
    windowTabs->addWidget(m_imagesWindow/*, tr("Images")*/);
    windowTabs->addWidget(m_paramsWindow/*, tr("Parameters")*/);
    windowTabs->addWidget(m_videoLinkWindow/*, tr("Video Link")*/);

    mainWidget->addWidget(m_modelList);
    mainWidget->addWidget(rightWidget);
    setCentralWidget(mainWidget);

    connect(m_execButton, SIGNAL(clicked()), this, SLOT(onExec()));
    connect(m_locateButton, SIGNAL(clicked()), this, SLOT(locateModelDir()));
    connect(m_autoPilotButton, SIGNAL(clicked(bool)), this, SLOT(autoPilot(bool)));
    connect(m_modelList, SIGNAL(itemDoubleClicked(QListWidgetItem*)), this, SLOT(onListItemDoubleClicked(QListWidgetItem*)));

    connect(m_imagesWindow, SIGNAL(finished()), this, SLOT(onFinishedSavingImages()));
}

QSize PageDler::sizeHint() const
{
    return QSize(800, 600);
}

void PageDler::getModels()
{
    Jcr::BrandPageParser* bpp = new Jcr::BrandPageParser();
    connect(bpp, SIGNAL(finished()), this, SLOT(onFinishedFetchingModelLinks()));
    bpp->run();
}

void PageDler::onGetModelLinks(const StdStringMap &modelLinks)
{
    m_modelList->clear();
    int totalCount = modelLinks.size();
    int finishedCount = 0;
    auto iter = modelLinks.begin();
    while (iter != modelLinks.end()) {

        // skip finished models
        QListWidgetItem* item = new QListWidgetItem;

        if (modelExists(iter.key().c_str())) {
            item->setTextColor(Qt::red);
            ++finishedCount;
        }

        item->setCheckState(Qt::Unchecked);
        item->setText(iter.key().c_str());
        item->setData(LinkRole, QVariant(iter.value().c_str()));
        m_modelList->addItem(item);
    }

    m_leftCountLabel->setText(tr("Total: %1, Left: %2").arg(totalCount).arg(totalCount - finishedCount));
    qDebug() << "model count: " << modelLinks.size();
}

void PageDler::onExec()
{
    qDebug() << "##############################################";
    m_imagesWindow->exec();
    m_paramsWindow->exec();
    m_videoLinkWindow->exec();
    m_statusLabel->setText(tr("Executing ..."));
}

void PageDler::autoPilot(bool auto_)
{
    m_isAutoPilot = auto_;
    int totalCount = m_modelList->count();
    int currIndex = m_modelList->currentRow();
    int leftCount = totalCount - currIndex + 1;
    qDebug() << "there're still " << leftCount << "items to go.";
    if (++currIndex >= totalCount) {
        QMessageBox::information(this, tr("Good News"), tr("All the models have been downloaded, Congratulations !!!"));
        return;
    }

    QListWidgetItem* nextItem = m_modelList->item(currIndex);
    m_modelList->setCurrentItem(nextItem);
    onListItemDoubleClicked(nextItem);

    if (auto_) {
        qDebug() << "Auto pilot mode is enabled.";
        onExec();
    }
}

void PageDler::onListItemDoubleClicked(QListWidgetItem *item)
{
    m_execLabel->setText(tr("Hold on ..."));
    m_statusLabel->setText(tr("Fetching data..."));
    m_imagesWindow->clear();
    m_videoLinkWindow->clear();
    item->setTextColor(Qt::blue);

    const QString model = item->text();
    QString brand = Jcr::DatabaseManager::instance()->brandName(model);
    const QUrl url(item->data(LinkRole).toString());

    //
    brand.replace("\\", "-");


    qDebug() << "model : " << item->text();
    qDebug() << "link: " << item->data(LinkRole).toString();
    m_brandLabel->setText(brand);

    Jcr::ModelPageParser* mpp = new ModelPageParser;
    connect(mpp, SIGNAL(finished()), this, SLOT(onFinishedParseModelPage()));
    mpp->setModelName(model);
    mpp->setBrandName(brand);
    mpp->setUrl(url);
    mpp->run();

    Jcr::ParametersPageParser* ppp = new Jcr::ParametersPageParser;
    connect(ppp, SIGNAL(finished()), this, SLOT(onFinishedParseParamsPage()));
    ppp->setModelName(model);
    ppp->setBrandName(brand);
    ppp->setUrl(Jcr::Utils::modelParametersUrl(url));
    ppp->run();
}

void PageDler::onFinishedFetchingModelLinks()
{
    Jcr::BrandPageParser* bpp = qobject_cast<Jcr::BrandPageParser*>(sender());
    m_modelList->clear();
    StdStringMap modelLinks = bpp->modelLinks();
    auto iter = modelLinks.begin();

    int totalCount = modelLinks.size();
    int finishedCount = 0;

    Jcr::DatabaseManager* dbMgr = Jcr::DatabaseManager::instance();
    QString model;
    while (iter != modelLinks.end()) {

        model = QString(iter.key().c_str());

        // if done parsing this model then do not load it on the listwidget
//        if (dbMgr->modelParamsExists(model) || dbMgr->brandName(model).isEmpty()) {
////            item->setTextColor(Qt::blue);
//            ++iter;
//            continue;
//        }

        QListWidgetItem* item = new QListWidgetItem;

        if (modelExists(model) && isModelDirEmpty(model)) {
            item->setTextColor(Qt::red); // means the model dir is there
            ++finishedCount;
        }

        item->setText(model);
        item->setData(LinkRole, QVariant(iter.value().c_str()));
        item->setToolTip(iter.value().c_str());
        m_modelList->addItem(item);

        ++iter;
    }

    m_leftCountLabel->setText(tr("Total: %1, Left: %2").arg(totalCount).arg(totalCount - finishedCount));

    bpp->deleteLater();
}

void PageDler::onFinishedParseModelPage()
{
    Jcr::ModelPageParser* mpp = qobject_cast<Jcr::ModelPageParser*>(sender());

    // process images
    QStringList imgLinks = mpp->imageLinks();
    m_imagesWindow->setBrandName(mpp->brandName());
    m_imagesWindow->setModelName(mpp->modelName());
    m_imagesWindow->setLinks(imgLinks);
    m_imagesWindow->exec();

    qDebug() << imgLinks;
    if (!imgLinks.isEmpty()) {
        m_gotImageLabel->setText(tr("Got image links"));
        m_gotImageLabel->setStyleSheet("color:green;");
    } else {
        m_gotImageLabel->setText(tr("No image links, now execute!"));
        m_gotImageLabel->setStyleSheet("color:red;");
    }

    // process video links
    QStringList videoLinks = mpp->videoLinks();
    m_videoLinkWindow->setBrandName(mpp->brandName());
    m_videoLinkWindow->setModelName(mpp->modelName());
    m_videoLinkWindow->setLinks(videoLinks);
    m_videoLinkWindow->exec();
}

void PageDler::onFinishedParseParamsPage()
{
    Jcr::ParametersPageParser* ppp = qobject_cast<Jcr::ParametersPageParser*>(sender());

    const QList<std::string>& params = ppp->parameters();
    m_paramsWindow->setModelName(ppp->modelName());
    m_paramsWindow->setBrandName(ppp->brandName());
    m_paramsWindow->setParameters(params);
    m_paramsWindow->exec();

    ppp->deleteLater();

    m_statusLabel->setText(tr("Got parameters, Now execute!"));
    m_execLabel->setText(tr("Params have been saved, now downloading images."));

    if (m_isAutoPilot) {
        ::Sleep(5000);
        autoPilot(true);
    }
}

void PageDler::onFinishedSavingImages()
{
    qDebug() << "Done saving images, next please ...";
}

void PageDler::locateModelDir()
{
    QListWidgetItem* item = m_modelList->currentItem();
    if (!item)
        return;

    const QString model = item->text();
    const QString brand = Jcr::DatabaseManager::instance()->brandName(model);
    const QString modelDir = QString("%1/%2/%3").arg(Jcr::IMAGEROOT).arg(brand).arg(model);
    const QString localePath = QDir::toNativeSeparators(modelDir);
    const QString strCmd("explorer.exe");
    const QStringList params = QStringList() << QString("/e,%1").arg(localePath);
    QProcess::startDetached(strCmd, params);
}

void PageDler::keyPressEvent(QKeyEvent *e)
{
    if ((e->modifiers() & Qt::ControlModifier) && (e->key() == Qt::Key_R))
        onExec();
}

bool PageDler::modelExists(const QString &model)
{
    QString brand = Jcr::DatabaseManager::instance()->brandName(model);
    QString path = QString("%1/%2/%3").arg(Jcr::IMAGEROOT).arg(brand).arg(model);
    bool exists = QFileInfo::exists(path);
    return exists;
}

bool PageDler::isModelDirEmpty(const QString &model)
{
    const QString brand = Jcr::DatabaseManager::instance()->brandName(model);
    const QString strModelDir = QString("%1/%2/%3").arg(Jcr::IMAGEROOT).arg(brand).arg(model);
    const QDir modelDir(strModelDir);
    QStringList files = modelDir.entryList(QDir::Files | QDir::NoDotAndDotDot);
    return files.isEmpty();
}

} // namespace jcr
